package com.guldan.jaina.task;

import com.guldan.core.constants.CommonConstant;
import com.guldan.core.constants.XlsHeaderConstant;
import com.guldan.core.enums.ProjectRegisterBatchEn;
import com.guldan.core.enums.ProjectRegisterEn;
import com.guldan.core.enums.ValidatingRegisterTypeEn;
import com.guldan.core.redis.CacheService;
import com.guldan.core.redis.DistributeLock;
import com.guldan.core.utils.MathUtil;
import com.guldan.jaina.dto.citizenbank.CitizenBankDTO;
import com.guldan.jaina.dto.citizeninfo.CitizenInfoDTO;
import com.guldan.jaina.dto.citizeninfo.CitizenInfoSearchDTO;
import com.guldan.jaina.dto.citizenproperty.CitizenPropertyDTO;
import com.guldan.jaina.dto.dictionary.DictionaryDTO;
import com.guldan.jaina.dto.progress.BarDTO;
import com.guldan.jaina.dto.projectextensiondetail.ProjectExtDataSampleDTO;
import com.guldan.jaina.dto.projectextensiondetail.ProjectExtensionDetailDTO;
import com.guldan.jaina.dto.projectregisterupload.ProjectRegisterUploadDTO;
import com.guldan.jaina.dto.register.RegisterTemplateDataDTO;
import com.guldan.jaina.dto.registerfail.RegisterFailDTO;
import com.guldan.jaina.dto.registersuccess.RegisterSuccessDTO;
import com.guldan.jaina.dto.users.UsersDTO;
import com.guldan.jaina.manager.*;
import com.guldan.jaina.utils.ComUtils;
import com.guldan.jaina.utils.UserUtils;
import com.guldan.jaina.utils.validating.CheckIdCard;
import com.guldan.mapper.db.entity.*;
import com.guldan.mapper.db.mapper.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Silas.
 * Date: 2016/12/20
 * Time: 15:22
 */
public class RegisterUploadThread implements Runnable {


    public Logger logger = LoggerFactory.getLogger(getClass());

    private BarDTO barDTO;

    private CitizenInfoMapperExt citizenInfoMapperExt;


    private ProjectExtensionDetailManager projectExtensionDetailManager;


    private CitizenBankMapperExt citizenBankMapperExt;


    private RegisterSuccessMapperExt registerSuccessMapperExt;


    private RegisterSuccessManager registerSuccessManager;


    private RegisterFailManager registerFailManager;


    private CitizenInfoManager citizenInfoManager;

    private CitizenPropertyManager citizenPropertyManager;

    private CitizenBankManager citizenBankManager;


    private HouseholdMapperExt householdMapperExt;

    private ProjectRegisterUploadManager projectRegisterUploadManager;

    private ProjectRegisterBatchMapperExt projectRegisterBatchMapperExt;

    private UsersDTO usersDTO;

    private CacheService cacheService;

    public void setCitizenPropertyManager(CitizenPropertyManager citizenPropertyManager) {
        this.citizenPropertyManager = citizenPropertyManager;
    }

    public void setProjectRegisterBatchMapperExt(ProjectRegisterBatchMapperExt projectRegisterBatchMapperExt) {
        this.projectRegisterBatchMapperExt = projectRegisterBatchMapperExt;
    }

    public void setProjectRegisterUploadManager(ProjectRegisterUploadManager projectRegisterUploadManager) {
        this.projectRegisterUploadManager = projectRegisterUploadManager;
    }

    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }

    public void setUsersDTO(UsersDTO usersDTO) {
        this.usersDTO = usersDTO;
    }

    public void setBarDTO(BarDTO barDTO) {
        this.barDTO = barDTO;
    }

    public void setCitizenInfoMapperExt(CitizenInfoMapperExt citizenInfoMapperExt) {
        this.citizenInfoMapperExt = citizenInfoMapperExt;
    }

    public void setProjectExtensionDetailManager(ProjectExtensionDetailManager projectExtensionDetailManager) {
        this.projectExtensionDetailManager = projectExtensionDetailManager;
    }

    public void setCitizenBankMapperExt(CitizenBankMapperExt citizenBankMapperExt) {
        this.citizenBankMapperExt = citizenBankMapperExt;
    }

    public void setRegisterSuccessMapperExt(RegisterSuccessMapperExt registerSuccessMapperExt) {
        this.registerSuccessMapperExt = registerSuccessMapperExt;
    }

    public void setRegisterSuccessManager(RegisterSuccessManager registerSuccessManager) {
        this.registerSuccessManager = registerSuccessManager;
    }

    public void setRegisterFailManager(RegisterFailManager registerFailManager) {
        this.registerFailManager = registerFailManager;
    }

    public void setCitizenInfoManager(CitizenInfoManager citizenInfoManager) {
        this.citizenInfoManager = citizenInfoManager;
    }

    public void setCitizenBankManager(CitizenBankManager citizenBankManager) {
        this.citizenBankManager = citizenBankManager;
    }

    public void setHouseholdMapperExt(HouseholdMapperExt householdMapperExt) {
        this.householdMapperExt = householdMapperExt;
    }

    private String threadName;

    private String[] header;

    private List<RegisterTemplateDataDTO> data;

    private Integer projectId;

    private Integer destBatchId;

    private Integer uploadId;

    private String projectPayCycleCode;

    private String projectOrgCode;

    private Integer year;

    private Integer[] extId;


    public void setHeader(String[] header) {
        this.header = header;
    }

    public void setData(List<RegisterTemplateDataDTO> data) {
        this.data = data;
    }

    public void setProjectId(Integer projectId) {
        this.projectId = projectId;
    }

    public void setDestBatchId(Integer destBatchId) {
        this.destBatchId = destBatchId;
    }

    public void setUploadId(Integer uploadId) {
        this.uploadId = uploadId;
    }

    public void setProjectPayCycleCode(String projectPayCycleCode) {
        this.projectPayCycleCode = projectPayCycleCode;
    }

    public void setProjectOrgCode(String projectOrgCode) {
        this.projectOrgCode = projectOrgCode;
    }

    public void setYear(Integer year) {
        this.year = year;
    }

    public void setExtId(Integer[] extId) {
        this.extId = extId;
    }

    public void setThreadName(String threadName) {
        this.threadName = threadName;
    }

    @Override
    public void run() {

        UserUtils.setUser(this.usersDTO);

        logger.info(this.threadName + " begin, this.data.size " + this.data.size());

        long cost = System.currentTimeMillis();
        DistributeLock lock = new DistributeLock();

        for (RegisterTemplateDataDTO dto : this.data) {

            try {

                /* lock begin */
                lock = new DistributeLock(String.format(CommonConstant.LOCK_KEY_UPLOAD_REGISTER_IdentNumber, dto.getIdentNumber()), cacheService);

                lock.lock1();
                /*while (!lock.lock()) {
                    Thread.sleep(300L);
                }*/

                logger.info(this.threadName + " ,1");

                Map<String, Object> map = validateAndUpdate(dto, this.destBatchId, this.uploadId, this.projectPayCycleCode, this.projectOrgCode);
                Integer validatingResult = (Integer) map.get("code");

                //deal project_extension_detail
                if (validatingResult.intValue() == ValidatingRegisterTypeEn.success.getCode().intValue()) {
//                successCount++;
                    this.barDTO.finishAdd(true);
                    if (header != null) {
                        BigDecimal[] values = dto.getValues();
//                        List<ProjectExtensionDetailDTO> pedList = new ArrayList<>();
                        for (int i = 0; i < header.length; i++) {
                            ProjectExtensionDetailDTO extDetailDto = new ProjectExtensionDetailDTO();
                            String extName = header[i];
                            extDetailDto.setBatchId(destBatchId);

                            //get extensions
                            if (values[i] == null || values[i].compareTo(BigDecimal.ZERO) == 0)
                                extDetailDto.setExtContent("0");
                            else
                                extDetailDto.setExtContent(new DecimalFormat("#.00").format(values[i]));
                            extDetailDto.setExtId(extId[i]);
                            extDetailDto.setExtName(extName);
                            extDetailDto.setProjectId(projectId);
                            extDetailDto.setYear(year);

                            extDetailDto.setRegisterId((Integer) map.get("registerId"));
                            projectExtensionDetailManager.save(extDetailDto);

//                            pedList.add(extDetailDto);
                        }

//                        JSONArray.fromObject(pedList).toString();
                    }

                } else {
                    //to do
//                failCount++;

                    this.barDTO.finishAdd(false);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                logger.info("getMessage111111************" + ex.getMessage());
                this.barDTO.finishAdd(false);
            } finally {

                lock.unLock1();
                //判断是否已经上传导入完成
                if (barDTO.getOver()) {
                    //更新上传记录表
                    ProjectRegisterUploadDTO projectRegisterUploadDTO = projectRegisterUploadManager.get(this.uploadId);
                    projectRegisterUploadDTO.setSuccessNum(barDTO.getSuccess());
                    projectRegisterUploadDTO.setFailNum(barDTO.getFail());
                    projectRegisterUploadManager.save(projectRegisterUploadDTO);
                }
            }
        }

        logger.info(this.threadName + " cost " + (System.currentTimeMillis() - cost));
    }

    public Map<String, Object> validateAndUpdate(RegisterTemplateDataDTO dto, Integer batchId, Integer uploadId, String projectPayCycleCode, String projectOrgCode) {

        StringBuilder failReason = new StringBuilder();

        Map<String, Object> map = new HashMap<String, Object>();

        CitizenInfo citizenInfo = null;

        //***********校验 非空
        //姓名
        if (StringUtils.isBlank(dto.getName())) {
            failReason.append(ComUtils.getFailReasonWithBlank(String.format(ValidatingRegisterTypeEn.emptyField.getMean()
                    , XlsHeaderConstant.REGISTER_XLS_HEADERS[0]) + ";"));
        }
        //身份证
        if (StringUtils.isBlank(dto.getIdentNumber())) {
            failReason.append(ComUtils.getFailReasonWithBlank(String.format(ValidatingRegisterTypeEn.emptyField.getMean()
                    , XlsHeaderConstant.REGISTER_XLS_HEADERS[1]) + ";"));
        } else {

            //校验身份证相关

            CheckIdCard cic = new CheckIdCard(dto.getIdentNumber());
            if (!cic.checkLength()) {
                //校验身份长度是是否是15位or18位
                failReason.append(ComUtils.getFailReasonWithBlank(ValidatingRegisterTypeEn.idCardLengthError.getMean() + ";"));
            } else {
//                if (!cic.validate()) {
//                    //校验身份证格式是否正确
//                    failReason.append(ComUtils.getFailReasonWithBlank(ValidatingRegisterTypeEn.idCardFormatError.getMean() + ";"));
//                } else {
                    //validating citizeninfo ，校验居民身份信息
                    //通过身份证号码查询
                    String name = dto.getName();
                    String identNumber = dto.getIdentNumber();
                    CitizenInfoExample example = new CitizenInfoExample();
                    CitizenInfoExample.Criteria criteria = example.createCriteria();

                    criteria.andIdentNumberEqualTo(identNumber);
                    criteria.andIsDeleteEqualTo(Boolean.FALSE);

                    List<CitizenInfo> citizenInfoList = citizenInfoMapperExt.selectByExample(example);

                    if (citizenInfoList == null || citizenInfoList.size() == 0) {
                        //不存在该身份证号码
                        failReason.append(ComUtils.getFailReasonWithBlank(ValidatingRegisterTypeEn.citizenNotFind.getMean() + ";"));
                        saveRegisterFail(dto, batchId, uploadId, failReason.toString());
                        map.put("code", ValidatingRegisterTypeEn.citizenNotFind.getCode());
                        return map;
                    } else {
                        citizenInfo = citizenInfoList.get(0);
                        dto.setAreaId(citizenInfo.getAreaId());  //修改登记记录中人的区划id为该人所在区划id

                        //校验名称是否一致
                        if (!citizenInfo.getName().equals(dto.getName())) {
                            //名字不一致
                            failReason.append(ValidatingRegisterTypeEn.citizenNotMatchName.getMean() + ";");

                        }

                        //validating bank number begin
                        //取出该人员银行卡信息，通过卡号，居民id查询
                        CitizenBankExample bankExample = new CitizenBankExample();
                        CitizenBankExample.Criteria bankCriteria = bankExample.createCriteria();
                        bankCriteria.andBankNumberEqualTo(dto.getBankNumber());
                        bankCriteria.andIsDeleteEqualTo(false);
                        bankCriteria.andCitizenInfoIdEqualTo(citizenInfo.getCitizenInfoId());

                        List<CitizenBank> citizenBankList = citizenBankMapperExt.selectByExample(bankExample);
                        if (citizenBankList == null || citizenBankList.size() == 0) {
                            //没查到卡号，
                            failReason.append(ComUtils.getFailReasonWithBlank(ValidatingRegisterTypeEn.citizenNotMatchBankNumber.getMean() + ";"));
                        } else {
                            CitizenBank cb = citizenBankList.get(0);
                            dto.setBankCode(cb.getBankCode());

                            DictionaryDTO dictionaryDTO = (DictionaryDTO) cacheService.getCache(String.format(CommonConstant.KEY_DIC, CommonConstant.DIC_TYPE_BANKCODE, cb.getBankCode()));
                            if (dictionaryDTO != null) {
                                if (!dictionaryDTO.getDictionaryName().equals(dto.getBankName())) {
                                    //execl中开户银行名字不匹配
                                    failReason.append(ComUtils.getFailReasonWithBlank(ValidatingRegisterTypeEn.citizenNotMatchBankName.getMean() + ";"));
                                }
                            }
                        }
                        //validating bank number end

                        //校验 已在%s区划中登记，%s批次中登记 begin
                        //先校验是否是特殊人员，不是特殊人员才进行校验
                        CitizenPropertyDTO citizenPropertyDTO = citizenPropertyManager.getByCitizenInfoId(citizenInfo.getCitizenInfoId());
                        if (citizenPropertyDTO.getSpecial() == null || !citizenPropertyDTO.getSpecial()) {
                            RegisterSuccessExample rsExample = new RegisterSuccessExample();
                            RegisterSuccessExample.Criteria rsCriteria = rsExample.createCriteria();
                            //rsCriteria.andAreaIdEqualTo(dto.getAreaId());   //项目登记区划
                            rsCriteria.andYearEqualTo(dto.getYear());   //年度，
                            rsCriteria.andProjectIdEqualTo(dto.getProjectId()); //项目id
                            rsCriteria.andSubsidyCountEqualTo(dto.getSubsidyCount());  //发放次数
                            rsCriteria.andIdentNumberEqualTo(dto.getIdentNumber());  //身份证号码
                            rsCriteria.andStateNotEqualTo(ProjectRegisterEn.bank_fail.getCode());    //剔除发放失败状态，发放失败状态可以再继续登记
                            rsCriteria.andIsDeleteEqualTo(false);    //过滤已经删除的
                            List<RegisterSuccess> registerSuccessList = registerSuccessMapperExt.selectByExample(rsExample);

                            if (registerSuccessList != null && registerSuccessList.size() > 0) {
                                //如果有，则取出，之前的登记批次信息，获取之前的登记区划信息
                                ProjectRegisterBatch oldPrb = projectRegisterBatchMapperExt.selectByPrimaryKey(registerSuccessList.get(0).getBatchId());

                                failReason.append(ComUtils.getFailReasonWithBlank(String.format(ValidatingRegisterTypeEn.hasOwnedSubsidyBatch.getMean(), oldPrb.getAreaName(), oldPrb.getYear() + "年第" + oldPrb.getSubsidyCount() + "次") + ";"));
                            }
                        }

                    }
//                }
            }
            //validating citizeninfo ，校验居民身份信息 end
        }
        //银行名称
        if (StringUtils.isBlank(dto.getBankName())) {
            failReason.append(ComUtils.getFailReasonWithBlank(String.format(ValidatingRegisterTypeEn.emptyField.getMean()
                    , XlsHeaderConstant.REGISTER_XLS_HEADERS[2]) + ";"));
        } else {
            //银行名称字典数据是否存在
            String bankCode = citizenInfoManager.getDicCodeByTypeAndValue(CommonConstant.DIC_TYPE_BANKCODE, dto.getBankName());
            if (StringUtils.isBlank(bankCode)) {
                failReason.append(ComUtils.getFailReasonWithBlank(ValidatingRegisterTypeEn.notFindBankName.getMean() + ";"));
            }
        }
        logger.info("222222222");
        //银行卡号
        if (StringUtils.isBlank(dto.getBankNumber())) {
            failReason.append(ComUtils.getFailReasonWithBlank(String.format(ValidatingRegisterTypeEn.emptyField.getMean()
                    , XlsHeaderConstant.REGISTER_XLS_HEADERS[3]) + ";"));
        } else {
            //校验是否为数字
            if (!MathUtil.isInteger(dto.getBankNumber())) {
                failReason.append(ComUtils.getFailReasonWithBlank(String.format(ValidatingRegisterTypeEn.formatError.getMean()
                        , XlsHeaderConstant.REGISTER_XLS_HEADERS[3]) + ";"));
            }
        }
        logger.info("3333333333");
        //校验金额
        double money = 0;
        try {
            if (StringUtils.isNotBlank(dto.getMoneyStr()))
                money = Double.parseDouble(dto.getMoneyStr());
            if (money < 0) {
                failReason.append(ComUtils.getFailReasonWithBlank(String.format(ValidatingRegisterTypeEn.moneyLessThan0.getMean(), XlsHeaderConstant.REGISTER_XLS_HEADERS[4]) + ";"));
            }
        } catch (Exception ex) {
            failReason.append(ComUtils.getFailReasonWithBlank(String.format(ValidatingRegisterTypeEn.formatError.getMean(), XlsHeaderConstant.REGISTER_XLS_HEADERS[4]) + ";"));
        }
        dto.setMoney(new BigDecimal(money));

        //************
        logger.info("4444444444");
        logger.info("55555555" + failReason.toString());
        logger.info("7777" + JSONObject.fromObject(dto).toString());
        //如果有校验不通过的规则，则需要写入失败表
        if (StringUtils.isNotBlank(failReason.toString())) {
            saveRegisterFail(dto, batchId, uploadId, failReason.toString());
            map.put("code", ValidatingRegisterTypeEn.idCardFormatError.getCode());
            return map;
        }

        logger.info("6666666");

        //通过所有校验，写入登记成功表
        try {
            RegisterSuccessDTO registerSuccessDTO = saveRegisterSuccess(dto, batchId, uploadId, projectPayCycleCode, projectOrgCode, citizenInfo.getCitizenInfoId());
            map.put("code", ValidatingRegisterTypeEn.success.getCode());
            map.put("registerId", registerSuccessDTO.getRegisterId());
        } catch (Exception ex) {
            logger.info("9999" + ex.getMessage());
        }
        logger.info("888888");

        return map;
    }

    /**
     * 写入失败表
     *
     * @param dto
     * @param uploadId
     */
    private RegisterFailDTO saveRegisterFail(RegisterTemplateDataDTO dto
            , Integer batchId, Integer uploadId
            , String failReason) {

        RegisterFailDTO record = new RegisterFailDTO();

        record.setUploadId(uploadId);
        record.setBatchId(batchId);

        //record.setCitizenInfoId();
        record.setProjectId(dto.getProjectId());
        record.setProjectName(dto.getProjectName());
        record.setYear(dto.getYear());
        record.setSubsidyCount(dto.getSubsidyCount());
        record.setRegisterAreaName(dto.getRegisterAreaName());
        record.setAreaName(dto.getAreaName());
        record.setName(dto.getName());
        record.setIdentNumber(dto.getIdentNumber());
        record.setBankName(dto.getBankName());
        record.setBankNumber(dto.getBankNumber());

//        record.setExtData(dto.getExtData());
        record.setFailReason(failReason);

        if (StringUtils.isBlank(dto.getMoneyStr())) dto.setMoneyStr("0.00");
        record.setSubsidyMoney(dto.getMoneyStr());

        if (header != null) {
            BigDecimal[] values = dto.getValues();
            List<ProjectExtDataSampleDTO> pedList = new ArrayList<>();
            for (int i = 0; i < header.length; i++) {
                ProjectExtDataSampleDTO extDetailDto = new ProjectExtDataSampleDTO();
                String extName = header[i];

                //get extensions
                if (values[i] == null || values[i].compareTo(BigDecimal.ZERO) == 0)
                    extDetailDto.setExtContent("0");
                else
                    extDetailDto.setExtContent(new DecimalFormat("#.00").format(values[i]));
                extDetailDto.setExtId(extId[i]);
                extDetailDto.setExtName(extName);

                pedList.add(extDetailDto);
            }

            record.setExtData(JSONArray.fromObject(pedList).toString());
        }


        return registerFailManager.save(record);
    }

    private RegisterSuccessDTO saveRegisterSuccess(RegisterTemplateDataDTO dto, Integer batchId, Integer uploadId, String projectPayCycleCode, String projectOrgCode, Integer citizenInfoId) {

        logger.info("batchId=" + batchId + " uploadId=" + uploadId + " citizenInfoId=" + citizenInfoId);
        logger.info("00000" + JSONObject.fromObject(UserUtils.getUser()));


        RegisterSuccessDTO record = new RegisterSuccessDTO();
        record.setUploadId(uploadId);
        record.setBatchId(batchId);
        record.setProjectId(dto.getProjectId());
        record.setOrgCode(projectOrgCode);
        record.setPayCycleCode(projectPayCycleCode);
        record.setYear(dto.getYear());
        record.setName(dto.getName());
        record.setSubsidyCount(dto.getSubsidyCount());
        record.setBankCode(dto.getBankCode());
        record.setBankNumber(dto.getBankNumber());
        record.setSubsidyMoney(new BigDecimal(new DecimalFormat("#.00").format(dto.getMoney())));

        if (UserUtils.isTowns()) {
            record.setState(ProjectRegisterEn.register_ing.getCode());
        } else {
            record.setState(ProjectRegisterEn.org_auditor_ing.getCode());
        }

        CitizenInfoDTO citizenInfo = citizenInfoManager.get(citizenInfoId);

        record.setAddress(citizenInfo.getAddress());
        record.setAddressZw(citizenInfo.getAddressZw());
        record.setAreaId(citizenInfo.getAreaId());
        record.setBirthday(citizenInfo.getBirthday());
        record.setCitizenInfoId(citizenInfo.getCitizenInfoId());
        record.setCitizenInfoTypeCode(citizenInfo.getCitizenInfoTypeCode());
        record.setDegreeCode(citizenInfo.getDegreeCode());
        record.setGenderCode(citizenInfo.getGenderCode());
        record.setAge(citizenInfo.getAge());
        record.setHouseholdId(citizenInfo.getHouseholdId());
        record.setHouseholdRegisterNumber(citizenInfo.getHouseholdRegisterNumber());
        record.setHouseHoldTypeCode(citizenInfo.getHouseHoldTypeCode());
        record.setIdentNumber(citizenInfo.getIdentNumber());
        record.setIdentTypeCode(citizenInfo.getIdentTypeCode());
        record.setMaster(citizenInfo.getMaster());
        record.setName(citizenInfo.getName());
        record.setNameZw(citizenInfo.getNameZw());
        record.setNationCode(citizenInfo.getNationCode());
        record.setRelationCode(citizenInfo.getRelationCode());
        record.setTelephone(citizenInfo.getTelephone());

        return registerSuccessManager.save(record);
    }


}
